/**
 * 自动获取焦点指令
 * @author luguoxiang
 * @date 2021-09-07
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
import { addEventListener, focus, nextId, removeEventListener } from '@/soar';

/**
 * 禁用
 * @param el
 * @param binding
 */
function disabled(el: any, binding: any) {
  if (binding.value) {
    el.setAttribute('disabled', 'disabled');
    el.classList.add('gl-disabled');
  } else {
    el.removeAttribute('disabled');
    el.classList.remove('gl-disabled');
  }
}

/**
 * 自动宫格
 * @param el
 * @param width
 * @constructor
 */
function LgGrid(el: any, width: number) {
  const count = Math.floor(el.clientWidth / width);
  if (count <= 1) {
    el.style.cssText = '--grid: 1';
  } else {
    el.style.cssText = `--grid: ${count}`;
  }
}

/**
 * 监听宽度变化
 */
const resizeListeners: any = {};
function removeResizeListener(el: any) {
  delete resizeListeners[el.$$lgid];
}
function addResizeListener(el: any, callback: Function) {
  if (!el.$$lgid) {
    el.$$lgid = nextId();
  }
  resizeListeners[el.$$lgid] = { el, callback };
}
function resizeListener() {
  for (const id in resizeListeners) {
    const item = resizeListeners[id];
    const { el } = item;
    if (item.clientWidth !== el.clientWidth) {
      item.clientWidth = el.clientWidth;
      item.callback(el);
      continue;
    }
    if (item.clientHeight !== el.clientHeight) {
      item.clientHeight = el.clientHeight;
      item.callback(el);
    }
  }
}
setInterval(resizeListener, 250);

function onRightClick(el: HTMLElement, config: any) {
  addEventListener(el, 'mouseover', function () {
    // @ts-ignore
    document._oncontextmenu = document.oncontextmenu;
    document.oncontextmenu = function (e) {
      e.preventDefault();
    };
  });
  addEventListener(el, 'mouseout', function () {
    // @ts-ignore
    document.oncontextmenu = document._oncontextmenu;
  });
  addEventListener(el, 'mouseup', function (e: any) {
    if (e.button === 2) {
      config!.value(e);
    }
  });
}

export default {
  /**
   * 自动获取焦点指令
   */
  focus,
  /**
   * 禁用
   */
  disabled: {
    mounted: disabled,
    updated: disabled,
  },
  /**
   * 监听元素宽高变化
   */
  onresize: {
    mounted(el: any, binding: any) {
      if (binding.modifiers.width) {
        // 监听宽度
        el.$LgOnresize = function () {
          const func = el.$LgOnresize;
          if (func.clientWidth !== el.clientWidth) {
            func.clientWidth = el.clientWidth;
            func.event(el);
          }
        };
      } else if (binding.modifiers.height) {
        // 监听高度变化
        el.$LgOnresize = function () {
          const func = el.$LgOnresize;
          if (func.clientHeight !== el.clientHeight) {
            func.clientHeight = el.clientHeight;
            func.event(el);
          }
        };
      } else {
        // 监听宽高变化
        el.$LgOnresize = function () {
          const func = el.$LgOnresize;
          if (func.clientWidth !== el.clientWidth) {
            func.clientWidth = el.clientWidth;
            func.event(el);
            return;
          }
          if (func.clientHeight !== el.clientHeight) {
            func.clientHeight = el.clientHeight;
            func.event(el);
          }
        };
      }

      el.$LgOnresize.event = binding.value;
      el.$LgOnresize();
      addResizeListener(el, el.$LgOnresize);
    },
    updated(el: any, binding: any) {
      el.$LgOnresize.event = binding.value;
    },
    unmounted(el: any, binding: any) {
      removeResizeListener(el);
      binding.value?.(el);
    },
  },
  /**
   * 自动宫格指令（根据配置的最小宽度实时计算宫格跨度）
   */
  grid: {
    mounted(el: any, binding: any) {
      el.classList.add('lg-grid-v');
      el.$LgGridValue = binding.value;

      LgGrid(el, el.$LgGridValue);
      addResizeListener(el, () => {
        LgGrid(el, el.$LgGridValue);
      });
    },
    updated(el: any, binding: any) {
      el.$LgGridValue = binding.value;
      LgGrid(el, el.$LgGridValue);
    },
    unmounted(el: any) {
      removeResizeListener(el);
    },
  },
  /**
   * 鼠标右键
   */
  onRightClick: {
    mounted: onRightClick,
  },
  /**
   * 获取焦点失去焦点事件绑定
   */
  activity: {
    mounted(element: any, b: any) {
      // @ts-ignore
      element.$$activityListener = {
        focus(event: any) {
          element.classList.add('is-focus');
          // 聚焦
          removeEventListener(element, b.arg ?? 'click', element.$$activityListener.focus);
          addEventListener(document, 'mousedown', element.$$activityListener.blur);

          if (typeof b.value === 'function') {
            b.value('focus', event);
          } else if (typeof b.value?.focus === 'function') {
            b.value.focus(event);
          }
        },
        blur(event: any) {
          if (event.path.findIndex((x: any) => x === element) === -1) {
            // 失焦
            element.classList.remove('is-focus');
            removeEventListener(document, 'mousedown', element.$$activityListener.blur);
            addEventListener(element, b.arg ?? 'click', element.$$activityListener.focus);

            if (typeof b.value === 'function') {
              b.value('blur', event);
            } else if (typeof b.value?.blur === 'function') {
              b.value.blur(event);
            }
          }
        },
      };
      // @ts-ignore
      addEventListener(element, b.arg ?? 'click', element.$$activityListener.focus);
    },
    unmounted(element: any, b: any) {
      removeEventListener(element, b.arg ?? 'click', element.$$activityListener.focus);
      removeEventListener(document, 'mousedown', element.$$activityListener.blur);
    },
  },
  /**
   * 字数超出省略
   */
  ellipsis: {
    mounted: (el: HTMLElement, binding: any) => {
      el.classList.add('lg-ellipsis');
      addEventListener(el, 'mouseover', (e: any) => {
        const top = e.clientY;
        const left = e.clientX;
        let div: any = el.querySelector('.v-ellipsis');
        if (!div) {
          div = document.createElement('div');
          div.className = 'v-ellipsis';
          el.appendChild(div);
        }
        div.style.cssText = `position: fixed; z-index: 9999; left: ${left}px; top: ${top}px;`;
        // @ts-ignore
        div.innerText = binding.value ?? el.childNodes[0].data;
      });
    },
  },
};
